local _G = getfenv(0);

local tostring = tostring;
local tonumber = tonumber;
local assert = assert;
local pcall = pcall;

local lower = string.lower;
local sub = string.sub;
local format = string.format;
local join = strjoin;



local ident, current, version = "", 0, 0;

-- Global print function!
ident, current = "GLOBAL_PRINT_FUNCTION!", 1;
version = _G[ident];
if (not version or version < current) then
	_G[ident] = current;
	local header_color = "7fffd4"; -- "33ff99"
		
	local function output(frame, header, msg)
		header = tostring(header);
		msg = tostring(msg);
		
		if (sub(lower(header), 1, 4) == "|cff" and (sub(lower(header), -3) == "|r:" or sub(lower(header), -3) == ":|r")) then -- Allready colorized
			frame:AddMessage(header .." "..msg, 1, 1, 1, nil, 5);
		else -- Default color
			if (sub(header, -1) == ":") then -- Scale away the semi-colon if it exists
				header = sub(header, 1, -2);
			end
			frame:AddMessage("|cff".. header_color .. header .."|r: "..msg, 1, 1, 1, nil, 5);
		end
	end
	
	local function arg_as_string(arg, ...)
		if select("#", ...) > 0 then
			return tostring(arg), arg_as_string(...);
		else
			return tostring(arg);
		end
	end
	
	local function print_args_sorted(frame, header, msg, ...)
		msg = tostring(msg);
		
		if msg:find("%%") and select('#', ...) >= 1 then
			local success, text = pcall(format, arg_as_string(msg, ...));
			
			if success then
				msg = text;
			end
		elseif (select("#", ...) > 0) then
			local success, text = pcall(join, " ", arg_as_string(msg, ...));
			
			if success then
				msg = text;
			end
		end
		
		output(frame, header, msg);
	end
	
	local function print_frame_sorted(frame, ...)
		local msg = tostring(select("1", ...));
		if (sub(msg, -1) == ":" or sub(lower(msg), -3) == ":|r") then
			print_args_sorted(frame, ...);
		else
			print_args_sorted(frame, "Output", ...);
		end
	end
	
	_G["print"] = function(...) -- Prints a message to default chatframe
		assert(select("#", ...) > 0, "bad argument #1 to 'print' (value expected)");
		
		print_frame_sorted(DEFAULT_CHAT_FRAME, ...);
	end
	
	_G["fprint"] = function(frame, ...) -- Prints a message to specified frame
		assert(type(frame) == "table", "bad argument #1 to 'fprint' (frame expected)");
		assert(type(frame.AddMessage) == "function", "bad argument #1 to 'fprint' (frame expected)");
		assert(select("#", ...) > 0, "bad argument #2 to 'fprint' (value expected)");
		
		print_frame_sorted(frame, ...);
	end
end -- print("AddOnName:", "Loaded!"); or fprint(ChatFrame2, "AddOnName:", "Loaded!");
-- I'd like this function to be able to take colors etc aswell but cba working on it more atm, for now it's enough!

--[[ a combined version could look like this, food for thought! and just deprecate fprint. drawback is one wouldn't know if it is argument 1 or 2 that is faulty ;)
	_G["print"] = function (frameORmsg, ...)
		if (frameORmsg and type(frameORmsg) == "table" and type(frameORmsg.AddMessage) == "function") then -- and type(frameORmsg.GetFrameType) == "function" and frameORmsg:GetFrameType() == "ScrollingMessageFrame") then
			assert(select("#", ...) > 0, "bad argument #1/2 to 'print' (value expected)");
			
			msg = tostring(select("1", ...) or nil);
			if (sub(msg, -1) == ":" or sub(lower(msg), -3) == ":|r") then
				print_args_sorted(frameORmsg, ...);
			else
				print_args_sorted(frameORmsg, "Output", ...);
			end
		else
			_G["print"](DEFAULT_CHAT_FRAME, frameORmsg, ...);
		end
	end
	
	_G["fprint"] = function(frame, ...) -- Prints a message to specified frame
		_G["print"](DEFAULT_CHAT_FRAME, "'fprint' is deprecated, please use print instead");
	end
	]]


--[[
	    bad argument #1 to 'tostring' (value expected)
	    
	    ??? separate print / printf and fprint / fprintf ???
	    - print(arg1, arg2) etc
	    - printf("%s %s", arg2, arg3);
	    - fprint(ChatFrame2, arg1, arg2);
	    - fprintf(ChatFrame2, "%s %s", arg2, arg3);
]]

--[[ Tests

print( "Test 1 - 4 lines")
print( "\124cff00FF00Cool:\124r", "printing", "some", "stuff!")
print( "\124cff00FF00Cool\124r:", "printing", "some", "stuff!")
print( "Cool:", "printing", "some", "stuff!")
print( "printing", "some", "stuff!")

print( "Test 2 - 4 lines")
print( "\124cff00FF00Cool:\124r", "printing %s %s!", "some", "stuff!")
print( "\124cff00FF00Cool\124r:", "printing %s %s!", "some", "stuff!")
print( "Cool:", "printing %s %s!", "some", "stuff!")
print( "printing %s %s!", "some", "stuff!")

fprint( ChatFrame2, "Test 1 - 4 lines")
fprint( ChatFrame2, "\124cff00FF00Cool:\124r", "printing", "some", "stuff!")
fprint( ChatFrame2, "\124cff00FF00Cool\124r:", "printing", "some", "stuff!")
fprint( ChatFrame2, "Cool:", "printing", "some", "stuff!")
fprint( ChatFrame2, "printing", "some", "stuff!")

fprint( ChatFrame2, "Test 2 - 4 lines")
fprint( ChatFrame2, "\124cff00FF00Cool:\124r", "printing %s %s!", "some", "stuff!")
fprint( ChatFrame2, "\124cff00FF00Cool\124r:", "printing %s %s!", "some", "stuff!")
fprint( ChatFrame2, "Cool:", "printing %s %s!", "some", "stuff!")
fprint( ChatFrame2, "printing %s %s!", "some", "stuff!")

]]